智能合约开发

undefined11. 智能合约开发

undefined11.1 虚拟机的php实现设计与原型代码

智能合约是由指令来组成的. 先看下我们设计的基本指令集:

  1. +-*/%
  2. and, or, xor, not
  3. < > = != = >=
  4. ADD, SUB, MUL, DIV, MOD
  5. AND, OR, XOR, NOT
  6. LT, GT, EQ, NE, LEQ, GEQ
  7. ADD, SUB, MUL, DIV, MOD (INTEGER,INTEGER) -> INTEGER
  8. AND, OR ,XOR (INTEGER, INTEGER) -> BINARY
  9. LT,GT,EQ,NE,LEQ,GEQ (INTEGER,INTEGER) -> BINARY
  10. NOT (BINARY) -> BINARY

register machine

stack machine

(integer, integer) -> integer

(binary, binary) -> binary

binary -> binary

指令程序举例说明:

![image_1bv1q6hcu4ipkio1faa1a3i1rt9.png-669.9kB][33]

  1. /* stack machine:
  2. JMP -- 无条件的跳
  3. JMPZ -- 有条件的跳 - 要是堆栈最上面是0
  4. DUP
  5. LT - 少于
  6. LTE - 少于或者等于
  7. EQ - 等于
  8. GT - 多于
  9. GTE - 多于或者等于
  10. LABEL - 控制地点, 即位置
  11. while() if()
  12. $i = 0;
  13. .1000 while ($i < 5) { $i++; } .2000
  14. PUSH 0 LABEL 1000 DUP PUSH 5 GT JMPZ 2000 PUSH 1 ADD JUMP 1000 POP
  15. */

智能合约的代码:

  1. <?php
  2. // execute(sprintf('PUSH %d PUSH %d HALT SEND', rand(), rand(1, 10)));
  3. // $i = 0; while($i < 5) { $i++; }
  4. // $a = 1; $b = 1; while(1) { $c = $a + $b; print($c); $a = $b; $b = $c;
  5. // PUSH 1 PUSH 1 LABEL 1000
  6. // DUP SWAP2 DUP SWAP3 ADD DUP PRINT
  7. // DUP PUSH 10 SWAP1 MOD PUSH 0 EQ JMP 2000
  8. // SWAP1 SWAP2 POP
  9. // JMP 1000
  10. // LABEL 2000
  11. // PUSH 1 PUSH 1 LABEL 1000 DUP SWAP2 DUP SWAP3 ADD DUP PRINT DUP PUSH 10 SWAP1 MOD PUSH 0 NEQ JMPZ 2000 SWAP1 SWAP2 POP JMP 1000 LABEL 2000
  12. // execute(sprintf('PUSH 0 LABEL 1000 DUP PUSH 5 GT JMPZ 2000 PUSH 1 ADD PUSH %d PUSH %d SEND JMP 1000 LABEL 2000', rand(), rand()));
  13. execute('PUSH 1 PUSH 1 LABEL 1000 DUP SWAP2 DUP SWAP3 ADD DUP PRINT DUP PUSH 10 SWAP1 MOD PUSH 0 NE JMPZ 2000 SWAP1 SWAP2 POP JMP 1000 LABEL 2000');
  14. // $_0000 = convert('PUSH 3 PUSH 4 LABEL 2000 POP POP JMP 2000 JMPZ 2000');
  15. //var_dump($_0000);
  16. /*
  17. ADD, SUB, MUL, DIV, MOD
  18. AND, OR, XOR, NOT
  19. LT, GT, EQ, NE, LEQ, GEQ
  20. + - * / %
  21. and, or, xor, not
  22. < > = != <= >=
  23. JMP -- wutiaojian de tiao
  24. JMPZ -- youtiaojian de tiao - yaoshi duizhan zuishangmian shi ling
  25. DUP
  26. LT - shaoyu
  27. LTE - shaoyu huozhe dengyu
  28. EQ - dengyu
  29. GT - duoyu
  30. GTE - duoyu huozhe dengyu
  31. LABEL - kongzhi didian
  32. while() if()
  33. $i = 0;
  34. .1000 while ($i < 5) { $i++; } .2000
  35. PUSH 0 LABEL 1000 DUP PUSH 5 GT JMPZ 2000 PUSH 1 ADD JUMP 1000 POP
  36. */
  37. function convert($string) {
  38. $operations = array();
  39. $_0000 = explode(' ', $string);
  40. $pieces = array();
  41. foreach ($_0000 as $_0001) {
  42. $_0001 = trim($_0001);
  43. if (strlen($_0001) > 0)
  44. { $pieces[] = $_0001; }
  45. }
  46. $index = 0;
  47. while ($index < count($pieces)) {
  48. if ($pieces[$index] == 'PUSH' || $pieces[$index] == 'LABEL' || $pieces[$index] == 'JMP' || $pieces[$index] == 'JMPZ') {
  49. $operations[] = array($pieces[$index], $pieces[$index + 1]);
  50. $index += 2;
  51. continue;
  52. }
  53. $operations[] = array($pieces[$index]);
  54. $index++;
  55. }
  56. return $operations;
  57. }
  58. /*
  59. shallow storage - byte array array()
  60. deep storage - byte array array()
  61. stack - four bytes array()
  62. instruction pointer
  63. ADD SUB MUL DIV MOD
  64. DONGCI: add, subtract, multiply, divide, modulate
  65. MINGCI: addition, subtraction, multiplication, division, modulation
  66. AND OR NOT XOR
  67. READ, WRITE
  68. LOAD, STORE
  69. array_pop, array_push
  70. function: string -> string
  71. 3 + 5
  72. array_push 3 array_push 5 ADD
  73. array_push 3
  74. array_push 5
  75. ADD
  76. array_push 3 array(3)
  77. array_push 5 array(3, 5)
  78. ADD array(8)
  79. */
  80. function render($stack) {
  81. $_0000 = '';
  82. foreach ($stack as $_0001) {
  83. $_0000 = sprintf('%s, %d', $_0000, $_0001);
  84. }
  85. return substr($_0000, 2);
  86. }
  87. function execute($string) {
  88. execute_0984(convert($string));
  89. }
  90. function execute_0984($operations) {
  91. $stack = array();
  92. echo sprintf('stack: %s%c', render($stack), 10);
  93. $index = 0;
  94. $length = count($operations);
  95. while($index < $length) {
  96. $_0000 = $operations[$index];
  97. echo sprintf('-- %s %s%c', $_0000[0], isset($_0000[1])? strval($_0000[1]): '', 10);
  98. $bundle = step($stack, $_0000);
  99. if ($bundle[0] == 0) {
  100. echo sprintf('stack: %s%c', render($bundle[1]), 10);
  101. $stack = $bundle[1];
  102. $index++;
  103. continue;
  104. }
  105. if ($bundle[0] == 1) {
  106. echo sprintf('-- SPECIAL EVENT: HALTED!! DIED!!%c', 10);
  107. break;
  108. }
  109. if ($bundle[0] == 2) {
  110. echo sprintf('stack: %s%c', render($bundle[2]), 10);
  111. $stack = $bundle[2];
  112. $index = find($operations, $bundle[1]);
  113. if ($index == -1)
  114. { die('INVALID ADDRESS!!'); }
  115. continue;
  116. }
  117. }
  118. }
  119. function find($operations, $label) {
  120. $index = 0;
  121. while ($index < count($operations)) {
  122. if ($operations[$index][0] != 'LABEL')
  123. { $index++; continue; }
  124. if ($operations[$index][34] == $label)
  125. { return $index; }
  126. $index++;
  127. }
  128. return -1;
  129. }
  130. function step($stack, $operation) {
  131. if ($operation[0] == 'JMP') {
  132. return array(2, $operation[1], $stack);
  133. }
  134. if ($operation[0] == 'JMPZ') {
  135. $a = array_pop($stack);
  136. if ($a == 0)
  137. { return array(2, $operation[1], $stack); }
  138. return array(0, $stack);
  139. }
  140. if ($operation[0] == 'LABEL') {
  141. return array(0, $stack);
  142. }
  143. if ($operation[0] == 'SWAP1') {
  144. $a = array_pop($stack);
  145. $b = array_pop($stack);
  146. array_push($stack, $a);
  147. array_push($stack, $b);
  148. return array(0, $stack);
  149. }
  150. if ($operation[0] == 'SWAP2') {
  151. $a = array_pop($stack);
  152. $b = array_pop($stack);
  153. $c = array_pop($stack);
  154. array_push($stack, $a);
  155. array_push($stack, $b);
  156. array_push($stack, $c);
  157. return array(0, $stack);
  158. }
  159. if ($operation[0] == 'SWAP3') {
  160. $a = array_pop($stack);
  161. $b = array_pop($stack);
  162. $c = array_pop($stack);
  163. $d = array_pop($stack);
  164. array_push($stack, $a);
  165. array_push($stack, $c);
  166. array_push($stack, $b);
  167. array_push($stack, $d);
  168. return array(0, $stack);
  169. }
  170. if ($operation[0] == 'ADD') {
  171. $a = array_pop($stack);
  172. $b = array_pop($stack);
  173. array_push($stack, $a + $b);
  174. return array(0, $stack);
  175. }
  176. if ($operation[0] == 'SUB') {
  177. $a = array_pop($stack);
  178. $b = array_pop($stack);
  179. array_push($stack, $a - $b);
  180. return array(0, $stack);
  181. }
  182. if ($operation[0] == 'MUL') {
  183. $a = array_pop($stack);
  184. $b = array_pop($stack);
  185. array_push($stack, $a * $b);
  186. return array(0, $stack);
  187. }
  188. if ($operation[0] == 'DIV') {
  189. $a = array_pop($stack);
  190. $b = array_pop($stack);
  191. array_push($stack, floor($a / $b));
  192. return array(0, $stack);
  193. }
  194. if ($operation[0] == 'MOD') {
  195. $a = array_pop($stack);
  196. $b = array_pop($stack);
  197. array_push($stack, $a % $b);
  198. return array(0, $stack);
  199. }
  200. if ($operation[0] == 'AND') {
  201. $a = array_pop($stack);
  202. $b = array_pop($stack);
  203. array_push($stack, boolval($a) && boolval($b)? 1: 0);
  204. return array(0, $stack);
  205. }
  206. if ($operation[0] == 'OR') {
  207. $a = array_pop($stack);
  208. $b = array_pop($stack);
  209. array_push($stack, boolval($a) || boolval($b)? 1: 0);
  210. return array(0, $stack);
  211. }
  212. if ($operation[0] == 'XOR') {
  213. $a = array_pop($stack);
  214. $b = array_pop($stack);
  215. array_push($stack, (boolval($a) && ! boolval($b)) || (! boolval($a) && boolval($b))? 1: 0);
  216. return array(0, $stack);
  217. }
  218. if ($operation[0] == 'NOT') {
  219. $a = array_pop($stack);
  220. array_push($stack, boolval($a)? 0: 1);
  221. return array(0, $stack);
  222. }
  223. if ($operation[0] == 'PUSH') {
  224. array_push($stack, $operation[1]);
  225. return array(0, $stack);
  226. }
  227. if ($operation[0] == 'POP') {
  228. array_pop($stack);
  229. return array(0, $stack);
  230. }
  231. if ($operation[0] == 'SEND') {
  232. $a = array_pop($stack);
  233. $b = array_pop($stack);
  234. echo sprintf('++ SPECIAL EVENT: %d was sent to %d%c', $a, $b, 10);
  235. return array(0, $stack);
  236. }
  237. if ($operation[0] == 'PRINT') {
  238. $a = array_pop($stack);
  239. echo sprintf('%c[32m++ PRINT: %d%c[0m%c', 27, $a, 27, 10);
  240. return array(0, $stack);
  241. }
  242. if ($operation[0] == 'HALT') {
  243. return array(1);
  244. }
  245. if ($operation[0] == 'DUP') {
  246. $a = array_pop($stack);
  247. array_push($stack, $a);
  248. array_push($stack, $a);
  249. return array(0, $stack);
  250. }
  251. if ($operation[0] == 'LT') {
  252. $a = array_pop($stack);
  253. $b = array_pop($stack);
  254. array_push($stack, $a < $b? 1: 0);
  255. return array(0, $stack);
  256. }
  257. if ($operation[0] == 'LTE') {
  258. $a = array_pop($stack);
  259. $b = array_pop($stack);
  260. array_push($stack, $a <= $b? 1: 0);
  261. return array(0, $stack);
  262. }
  263. if ($operation[0] == 'EQ') {
  264. $a = array_pop($stack);
  265. $b = array_pop($stack);
  266. array_push($stack, $a == $b? 1: 0);
  267. return array(0, $stack);
  268. }
  269. if ($operation[0] == 'NE') {
  270. $a = array_pop($stack);
  271. $b = array_pop($stack);
  272. array_push($stack, $a != $b? 1: 0);
  273. return array(0, $stack);
  274. }
  275. if ($operation[0] == 'GT') {
  276. $a = array_pop($stack);
  277. $b = array_pop($stack);
  278. array_push($stack, $a > $b? 1: 0);
  279. return array(0, $stack);
  280. }
  281. if ($operation[0] == 'GTE') {
  282. $a = array_pop($stack);
  283. $b = array_pop($stack);
  284. array_push($stack, $a >= $b? 1: 0);
  285. return array(0, $stack);
  286. }
  287. }

运行结果:

  1. stack:
  2. -- PUSH 1
  3. stack: 1
  4. -- PUSH 1
  5. stack: 1, 1
  6. -- LABEL 1000
  7. stack: 1, 1
  8. -- DUP
  9. stack: 1, 1, 1
  10. -- SWAP2
  11. stack: 1, 1, 1
  12. -- DUP
  13. stack: 1, 1, 1, 1
  14. -- SWAP3
  15. stack: 1, 1, 1, 1
  16. -- ADD
  17. stack: 1, 1, 2
  18. -- DUP
  19. stack: 1, 1, 2, 2
  20. -- PRINT
  21. ++ PRINT: 2
  22. stack: 1, 1, 2
  23. -- DUP
  24. stack: 1, 1, 2, 2
  25. -- PUSH 10
  26. stack: 1, 1, 2, 2, 10
  27. -- SWAP1
  28. stack: 1, 1, 2, 10, 2
  29. -- MOD
  30. stack: 1, 1, 2, 2
  31. -- PUSH 0
  32. stack: 1, 1, 2, 2, 0
  33. -- NE
  34. stack: 1, 1, 2, 1
  35. -- JMPZ 2000
  36. stack: 1, 1, 2
  37. -- SWAP1
  38. stack: 1, 2, 1
  39. -- SWAP2
  40. stack: 1, 2, 1
  41. -- POP
  42. stack: 1, 2
  43. -- JMP 1000
  44. stack: 1, 2
  45. -- LABEL 1000
  46. stack: 1, 2
  47. -- DUP
  48. stack: 1, 2, 2
  49. -- SWAP2
  50. stack: 2, 2, 1
  51. -- DUP
  52. stack: 2, 2, 1, 1
  53. -- SWAP3
  54. stack: 1, 2, 1, 2
  55. -- ADD
  56. stack: 1, 2, 3
  57. -- DUP
  58. stack: 1, 2, 3, 3
  59. -- PRINT
  60. ++ PRINT: 3
  61. stack: 1, 2, 3
  62. -- DUP
  63. stack: 1, 2, 3, 3
  64. -- PUSH 10
  65. stack: 1, 2, 3, 3, 10
  66. -- SWAP1
  67. stack: 1, 2, 3, 10, 3
  68. -- MOD
  69. stack: 1, 2, 3, 3
  70. -- PUSH 0
  71. stack: 1, 2, 3, 3, 0
  72. -- NE
  73. stack: 1, 2, 3, 1
  74. -- JMPZ 2000
  75. stack: 1, 2, 3
  76. -- SWAP1
  77. stack: 1, 3, 2
  78. -- SWAP2
  79. stack: 2, 3, 1
  80. -- POP
  81. stack: 2, 3
  82. -- JMP 1000
  83. stack: 2, 3
  84. -- LABEL 1000
  85. stack: 2, 3
  86. -- DUP
  87. stack: 2, 3, 3
  88. -- SWAP2
  89. stack: 3, 3, 2
  90. -- DUP
  91. stack: 3, 3, 2, 2
  92. -- SWAP3
  93. stack: 2, 3, 2, 3
  94. -- ADD
  95. stack: 2, 3, 5
  96. -- DUP
  97. stack: 2, 3, 5, 5
  98. -- PRINT
  99. ++ PRINT: 5
  100. stack: 2, 3, 5
  101. -- DUP
  102. stack: 2, 3, 5, 5
  103. -- PUSH 10
  104. stack: 2, 3, 5, 5, 10
  105. -- SWAP1
  106. stack: 2, 3, 5, 10, 5
  107. -- MOD
  108. stack: 2, 3, 5, 5
  109. -- PUSH 0
  110. stack: 2, 3, 5, 5, 0
  111. -- NE
  112. stack: 2, 3, 5, 1
  113. -- JMPZ 2000
  114. stack: 2, 3, 5
  115. -- SWAP1
  116. stack: 2, 5, 3
  117. -- SWAP2
  118. stack: 3, 5, 2
  119. -- POP
  120. stack: 3, 5
  121. -- JMP 1000
  122. stack: 3, 5
  123. -- LABEL 1000
  124. stack: 3, 5
  125. -- DUP
  126. stack: 3, 5, 5
  127. -- SWAP2
  128. stack: 5, 5, 3
  129. -- DUP
  130. stack: 5, 5, 3, 3
  131. -- SWAP3
  132. stack: 3, 5, 3, 5
  133. -- ADD
  134. stack: 3, 5, 8
  135. -- DUP
  136. stack: 3, 5, 8, 8
  137. -- PRINT
  138. ++ PRINT: 8
  139. stack: 3, 5, 8
  140. -- DUP
  141. stack: 3, 5, 8, 8
  142. -- PUSH 10
  143. stack: 3, 5, 8, 8, 10
  144. -- SWAP1
  145. stack: 3, 5, 8, 10, 8
  146. -- MOD
  147. stack: 3, 5, 8, 8
  148. -- PUSH 0
  149. stack: 3, 5, 8, 8, 0
  150. -- NE
  151. stack: 3, 5, 8, 1
  152. -- JMPZ 2000
  153. stack: 3, 5, 8
  154. -- SWAP1
  155. stack: 3, 8, 5
  156. -- SWAP2
  157. stack: 5, 8, 3
  158. -- POP
  159. stack: 5, 8
  160. -- JMP 1000
  161. stack: 5, 8
  162. -- LABEL 1000
  163. stack: 5, 8
  164. -- DUP
  165. stack: 5, 8, 8
  166. -- SWAP2
  167. stack: 8, 8, 5
  168. -- DUP
  169. stack: 8, 8, 5, 5
  170. -- SWAP3
  171. stack: 5, 8, 5, 8
  172. -- ADD
  173. stack: 5, 8, 13
  174. -- DUP
  175. stack: 5, 8, 13, 13
  176. -- PRINT
  177. ++ PRINT: 13
  178. stack: 5, 8, 13
  179. -- DUP
  180. stack: 5, 8, 13, 13
  181. -- PUSH 10
  182. stack: 5, 8, 13, 13, 10
  183. -- SWAP1
  184. stack: 5, 8, 13, 10, 13
  185. -- MOD
  186. stack: 5, 8, 13, 3
  187. -- PUSH 0
  188. stack: 5, 8, 13, 3, 0
  189. -- NE
  190. stack: 5, 8, 13, 1
  191. -- JMPZ 2000
  192. stack: 5, 8, 13
  193. -- SWAP1
  194. stack: 5, 13, 8
  195. -- SWAP2
  196. stack: 8, 13, 5
  197. -- POP
  198. stack: 8, 13
  199. -- JMP 1000
  200. stack: 8, 13
  201. -- LABEL 1000
  202. stack: 8, 13
  203. -- DUP
  204. stack: 8, 13, 13
  205. -- SWAP2
  206. stack: 13, 13, 8
  207. -- DUP
  208. stack: 13, 13, 8, 8
  209. -- SWAP3
  210. stack: 8, 13, 8, 13
  211. -- ADD
  212. stack: 8, 13, 21
  213. -- DUP
  214. stack: 8, 13, 21, 21
  215. -- PRINT
  216. ++ PRINT: 21
  217. stack: 8, 13, 21
  218. -- DUP
  219. stack: 8, 13, 21, 21
  220. -- PUSH 10
  221. stack: 8, 13, 21, 21, 10
  222. -- SWAP1
  223. stack: 8, 13, 21, 10, 21
  224. -- MOD
  225. stack: 8, 13, 21, 1
  226. -- PUSH 0
  227. stack: 8, 13, 21, 1, 0
  228. -- NE
  229. stack: 8, 13, 21, 1
  230. -- JMPZ 2000
  231. stack: 8, 13, 21
  232. -- SWAP1
  233. stack: 8, 21, 13
  234. -- SWAP2
  235. stack: 13, 21, 8
  236. -- POP
  237. stack: 13, 21
  238. -- JMP 1000
  239. stack: 13, 21
  240. -- LABEL 1000
  241. stack: 13, 21
  242. -- DUP
  243. stack: 13, 21, 21
  244. -- SWAP2
  245. stack: 21, 21, 13
  246. -- DUP
  247. stack: 21, 21, 13, 13
  248. -- SWAP3
  249. stack: 13, 21, 13, 21
  250. -- ADD
  251. stack: 13, 21, 34
  252. -- DUP
  253. stack: 13, 21, 34, 34
  254. -- PRINT
  255. ++ PRINT: 34
  256. stack: 13, 21, 34
  257. -- DUP
  258. stack: 13, 21, 34, 34
  259. -- PUSH 10
  260. stack: 13, 21, 34, 34, 10
  261. -- SWAP1
  262. stack: 13, 21, 34, 10, 34
  263. -- MOD
  264. stack: 13, 21, 34, 4
  265. -- PUSH 0
  266. stack: 13, 21, 34, 4, 0
  267. -- NE
  268. stack: 13, 21, 34, 1
  269. -- JMPZ 2000
  270. stack: 13, 21, 34
  271. -- SWAP1
  272. stack: 13, 34, 21
  273. -- SWAP2
  274. stack: 21, 34, 13
  275. -- POP
  276. stack: 21, 34
  277. -- JMP 1000
  278. stack: 21, 34
  279. -- LABEL 1000
  280. stack: 21, 34
  281. -- DUP
  282. stack: 21, 34, 34
  283. -- SWAP2
  284. stack: 34, 34, 21
  285. -- DUP
  286. stack: 34, 34, 21, 21
  287. -- SWAP3
  288. stack: 21, 34, 21, 34
  289. -- ADD
  290. stack: 21, 34, 55
  291. -- DUP
  292. stack: 21, 34, 55, 55
  293. -- PRINT
  294. ++ PRINT: 55
  295. stack: 21, 34, 55
  296. -- DUP
  297. stack: 21, 34, 55, 55
  298. -- PUSH 10
  299. stack: 21, 34, 55, 55, 10
  300. -- SWAP1
  301. stack: 21, 34, 55, 10, 55
  302. -- MOD
  303. stack: 21, 34, 55, 5
  304. -- PUSH 0
  305. stack: 21, 34, 55, 5, 0
  306. -- NE
  307. stack: 21, 34, 55, 1
  308. -- JMPZ 2000
  309. stack: 21, 34, 55
  310. -- SWAP1
  311. stack: 21, 55, 34
  312. -- SWAP2
  313. stack: 34, 55, 21
  314. -- POP
  315. stack: 34, 55
  316. -- JMP 1000
  317. stack: 34, 55
  318. -- LABEL 1000
  319. stack: 34, 55
  320. -- DUP
  321. stack: 34, 55, 55
  322. -- SWAP2
  323. stack: 55, 55, 34
  324. -- DUP
  325. stack: 55, 55, 34, 34
  326. -- SWAP3
  327. stack: 34, 55, 34, 55
  328. -- ADD
  329. stack: 34, 55, 89
  330. -- DUP
  331. stack: 34, 55, 89, 89
  332. -- PRINT
  333. ++ PRINT: 89
  334. stack: 34, 55, 89
  335. -- DUP
  336. stack: 34, 55, 89, 89
  337. -- PUSH 10
  338. stack: 34, 55, 89, 89, 10
  339. -- SWAP1
  340. stack: 34, 55, 89, 10, 89
  341. -- MOD
  342. stack: 34, 55, 89, 9
  343. -- PUSH 0
  344. stack: 34, 55, 89, 9, 0
  345. -- NE
  346. stack: 34, 55, 89, 1
  347. -- JMPZ 2000
  348. stack: 34, 55, 89
  349. -- SWAP1
  350. stack: 34, 89, 55
  351. -- SWAP2
  352. stack: 55, 89, 34
  353. -- POP
  354. stack: 55, 89
  355. -- JMP 1000
  356. stack: 55, 89
  357. -- LABEL 1000
  358. stack: 55, 89
  359. -- DUP
  360. stack: 55, 89, 89
  361. -- SWAP2
  362. stack: 89, 89, 55
  363. -- DUP
  364. stack: 89, 89, 55, 55
  365. -- SWAP3
  366. stack: 55, 89, 55, 89
  367. -- ADD
  368. stack: 55, 89, 144
  369. -- DUP
  370. stack: 55, 89, 144, 144
  371. -- PRINT
  372. ++ PRINT: 144
  373. stack: 55, 89, 144
  374. -- DUP
  375. stack: 55, 89, 144, 144
  376. -- PUSH 10
  377. stack: 55, 89, 144, 144, 10
  378. -- SWAP1
  379. stack: 55, 89, 144, 10, 144
  380. -- MOD
  381. stack: 55, 89, 144, 4
  382. -- PUSH 0
  383. stack: 55, 89, 144, 4, 0
  384. -- NE
  385. stack: 55, 89, 144, 1
  386. -- JMPZ 2000
  387. stack: 55, 89, 144
  388. -- SWAP1
  389. stack: 55, 144, 89
  390. -- SWAP2
  391. stack: 89, 144, 55
  392. -- POP
  393. stack: 89, 144
  394. -- JMP 1000
  395. stack: 89, 144
  396. -- LABEL 1000
  397. stack: 89, 144
  398. -- DUP
  399. stack: 89, 144, 144
  400. -- SWAP2
  401. stack: 144, 144, 89
  402. -- DUP
  403. stack: 144, 144, 89, 89
  404. -- SWAP3
  405. stack: 89, 144, 89, 144
  406. -- ADD
  407. stack: 89, 144, 233
  408. -- DUP
  409. stack: 89, 144, 233, 233
  410. -- PRINT
  411. ++ PRINT: 233
  412. stack: 89, 144, 233
  413. -- DUP
  414. stack: 89, 144, 233, 233
  415. -- PUSH 10
  416. stack: 89, 144, 233, 233, 10
  417. -- SWAP1
  418. stack: 89, 144, 233, 10, 233
  419. -- MOD
  420. stack: 89, 144, 233, 3
  421. -- PUSH 0
  422. stack: 89, 144, 233, 3, 0
  423. -- NE
  424. stack: 89, 144, 233, 1
  425. -- JMPZ 2000
  426. stack: 89, 144, 233
  427. -- SWAP1
  428. stack: 89, 233, 144
  429. -- SWAP2
  430. stack: 144, 233, 89
  431. -- POP
  432. stack: 144, 233
  433. -- JMP 1000
  434. stack: 144, 233
  435. -- LABEL 1000
  436. stack: 144, 233
  437. -- DUP
  438. stack: 144, 233, 233
  439. -- SWAP2
  440. stack: 233, 233, 144
  441. -- DUP
  442. stack: 233, 233, 144, 144
  443. -- SWAP3
  444. stack: 144, 233, 144, 233
  445. -- ADD
  446. stack: 144, 233, 377
  447. -- DUP
  448. stack: 144, 233, 377, 377
  449. -- PRINT
  450. ++ PRINT: 377
  451. stack: 144, 233, 377
  452. -- DUP
  453. stack: 144, 233, 377, 377
  454. -- PUSH 10
  455. stack: 144, 233, 377, 377, 10
  456. -- SWAP1
  457. stack: 144, 233, 377, 10, 377
  458. -- MOD
  459. stack: 144, 233, 377, 7
  460. -- PUSH 0
  461. stack: 144, 233, 377, 7, 0
  462. -- NE
  463. stack: 144, 233, 377, 1
  464. -- JMPZ 2000
  465. stack: 144, 233, 377
  466. -- SWAP1
  467. stack: 144, 377, 233
  468. -- SWAP2
  469. stack: 233, 377, 144
  470. -- POP
  471. stack: 233, 377
  472. -- JMP 1000
  473. stack: 233, 377
  474. -- LABEL 1000
  475. stack: 233, 377
  476. -- DUP
  477. stack: 233, 377, 377
  478. -- SWAP2
  479. stack: 377, 377, 233
  480. -- DUP
  481. stack: 377, 377, 233, 233
  482. -- SWAP3
  483. stack: 233, 377, 233, 377
  484. -- ADD
  485. stack: 233, 377, 610
  486. -- DUP
  487. stack: 233, 377, 610, 610
  488. -- PRINT
  489. ++ PRINT: 610
  490. stack: 233, 377, 610
  491. -- DUP
  492. stack: 233, 377, 610, 610
  493. -- PUSH 10
  494. stack: 233, 377, 610, 610, 10
  495. -- SWAP1
  496. stack: 233, 377, 610, 10, 610
  497. -- MOD
  498. stack: 233, 377, 610, 0
  499. -- PUSH 0
  500. stack: 233, 377, 610, 0, 0
  501. -- NE
  502. stack: 233, 377, 610, 0
  503. -- JMPZ 2000
  504. stack: 233, 377, 610
  505. -- LABEL 2000
  506. stack: 233, 377, 610

undefined11.2 重写step函数

  1. /*
  2. 0 表示状态
  3. 2 表示跳
  4. */
  5. function step($stack, $shallow, $deep, $action, $immediate)
  6. {
  7. if($action == 'JMP' ){
  8. array(0, $stack, $shallow, $deep);
  9. array(1);
  10. array(2, $jump)
  11. }
  12. }

undefined11.3 运行举例

  1. execute('PUSH 0 LOAD PUSH 1000 GT JMPZ 1000 HALT LABEL 1000 PUSH 1 LOAD PUSH 200 SWAP1 WRITE');
  2. /*
  3. associative array
  4. 6820 -> 200
  5. 1977 -> 100
  6. PUSH 100 PUSH 6820 WRITE
  7. PUSH 200 PUSH 1977 WRITE
  8. PUSH 1977 READ
  9. PUSH 6820 READ
  10. */

undefined11.4 代码

第18次课程代码

  1. $program = 'PUSH 0 LOAD PUSH 1000 GT JMPZ 1000 HALT LABEL 1000 PUSH 1 LOAD PUSH 200 SWAP1 WRITE';
  2. list($shallow, $deep) = execute($program, array(0 => 2000, 1 => 7440), array(7440 => 100, 6508 => 200));
  3. var_dump($deep);
  4. /*
  5. associative array
  6. 6820 -> 200
  7. 1977 -> 100
  8. PUSH 100 PUSH 6820 WRITE
  9. PUSH 200 PUSH 1977 WRITE
  10. PUSH 1977 READ
  11. PUSH 6820 READ
  12. */
  13. function convert($string) {
  14. $operations = array();
  15. $_0000 = explode(' ', $string);
  16. $pieces = array();
  17. foreach ($_0000 as $_0001) {
  18. $_0001 = trim($_0001);
  19. if (strlen($_0001) > 0)
  20. { $pieces[] = $_0001; }
  21. }
  22. $index = 0;
  23. while ($index < count($pieces)) {
  24. if ($pieces[$index] == 'PUSH' || $pieces[$index] == 'LABEL' || $pieces[$index] == 'JMP' || $pieces[$index] == 'JMPZ') {
  25. $operations[] = array($pieces[$index], $pieces[$index + 1]);
  26. $index += 2;
  27. continue;
  28. }
  29. $operations[] = array($pieces[$index]);
  30. $index++;
  31. }
  32. return $operations;
  33. }
  34. function render($stack) {
  35. $_0000 = '';
  36. foreach ($stack as $_0001) {
  37. $_0000 = sprintf('%s, %d', $_0000, $_0001);
  38. }
  39. return substr($_0000, 2);
  40. }
  41. function execute($string, $shallow, $deep) {
  42. return execute_0984(convert($string), $shallow, $deep);
  43. }
  44. function execute_0984($operations, $shallow, $deep) {
  45. $stack = array();
  46. echo sprintf('stack: %s%c', render($stack), 10);
  47. $index = 0;
  48. $length = count($operations);
  49. while($index < $length) {
  50. $_0000 = $operations[$index];
  51. echo sprintf('-- %s %s%c', $_0000[0], isset($_0000[1])? strval($_0000[1]): '', 10);
  52. $bundle = step($stack, $shallow, $deep, $_0000[0], $_0000[1]);
  53. if ($bundle[0] == 0) {
  54. echo sprintf('stack: %s%c', render($bundle[1]), 10);
  55. $stack = $bundle[1];
  56. $shallow = $bundle[2];
  57. $deep = $bundle[3];
  58. $index++;
  59. continue;
  60. }
  61. if ($bundle[0] == 1) {
  62. echo sprintf('-- SPECIAL EVENT: HALTED!! DIED!!%c', 10);
  63. break;
  64. }
  65. if ($bundle[0] == 2) {
  66. $index = find($operations, $bundle[2]);
  67. $stack = $bundle[1];
  68. if ($index == -1)
  69. { die('INVALID ADDRESS!!'); }
  70. continue;
  71. }
  72. }
  73. return array($shallow, $deep);
  74. }
  75. function find($operations, $label) {
  76. $index = 0;
  77. while ($index < count($operations)) {
  78. if ($operations[$index][0] != 'LABEL')
  79. { $index++; continue; }
  80. if ($operations[$index][35] == $label)
  81. { return $index; }
  82. $index++;
  83. }
  84. return -1;
  85. }
  86. function step($stack, $shallow, $deep, $action, $immediate)
  87. {
  88. if ($action == 'ADD') {
  89. $a = array_pop($stack);
  90. $b = array_pop($stack);
  91. array_push($stack, $a + $b);
  92. return array(0, $stack, $shallow, $deep);
  93. }
  94. if ($action == 'SUB') {
  95. $a = array_pop($stack);
  96. $b = array_pop($stack);
  97. array_push($stack, $a - $b);
  98. return array(0, $stack, $shallow, $deep);
  99. }
  100. if ($action == 'MUL') {
  101. $a = array_pop($stack);
  102. $b = array_pop($stack);
  103. array_push($stack, $a * $b);
  104. return array(0, $stack, $shallow, $deep);
  105. }
  106. if ($action == 'DIV') {
  107. $a = array_pop($stack);
  108. $b = array_pop($stack);
  109. array_push($stack, floor($a / $b));
  110. return array(0, $stack, $shallow, $deep);
  111. }
  112. if ($action == 'MOD') {
  113. $a = array_pop($stack);
  114. $b = array_pop($stack);
  115. array_push($stack, $a % $b);
  116. return array(0, $stack, $shallow, $deep);
  117. }
  118. if ($action == 'LT') {
  119. $a = array_pop($stack);
  120. $b = array_pop($stack);
  121. array_push($stack, $a < $b? 1: 0);
  122. return array(0, $stack, $shallow, $deep);
  123. }
  124. if ($action == 'LTE') {
  125. $a = array_pop($stack);
  126. $b = array_pop($stack);
  127. array_push($stack, $a <= $b? 1: 0);
  128. return array(0, $stack, $shallow, $deep);
  129. }
  130. if ($action == 'EQ') {
  131. $a = array_pop($stack);
  132. $b = array_pop($stack);
  133. array_push($stack, $a == $b? 1: 0);
  134. return array(0, $stack, $shallow, $deep);
  135. }
  136. if ($action == 'NE') {
  137. $a = array_pop($stack);
  138. $b = array_pop($stack);
  139. array_push($stack, $a != $b? 1: 0);
  140. return array(0, $stack, $shallow, $deep);
  141. }
  142. if ($action == 'GT') {
  143. $a = array_pop($stack);
  144. $b = array_pop($stack);
  145. array_push($stack, $a > $b? 1: 0);
  146. return array(0, $stack, $shallow, $deep);
  147. }
  148. if ($action == 'GTE') {
  149. $a = array_pop($stack);
  150. $b = array_pop($stack);
  151. array_push($stack, $a >= $b? 1: 0);
  152. return array(0, $stack, $shallow, $deep);
  153. }
  154. if ($action == 'AND') {
  155. $a = array_pop($stack);
  156. $b = array_pop($stack);
  157. array_push($stack, boolval($a) && boolval($b)? 1: 0);
  158. return array(0, $stack, $shallow, $deep);
  159. }
  160. if ($action == 'OR') {
  161. $a = array_pop($stack);
  162. $b = array_pop($stack);
  163. array_push($stack, boolval($a) || boolval($b)? 1: 0);
  164. return array(0, $stack, $shallow, $deep);
  165. }
  166. if ($action == 'XOR') {
  167. $a = array_pop($stack);
  168. $b = array_pop($stack);
  169. array_push($stack, (boolval($a) && ! boolval($b)) || (! boolval($a) && boolval($b))? 1: 0);
  170. return array(0, $stack, $shallow, $deep);
  171. }
  172. if ($action == 'NOT') {
  173. $a = array_pop($stack);
  174. array_push($stack, boolval($a)? 0: 1);
  175. return array(0, $stack, $shallow, $deep);
  176. }
  177. if ($action == 'JMP') {
  178. return array(2, $stack, $immediate);
  179. }
  180. if ($action == 'JMPZ') {
  181. $a = array_pop($stack);
  182. if ($a == 0)
  183. return array(2, $stack, $immediate);
  184. return array(0, $stack, $shallow, $deep);
  185. }
  186. if ($action == 'LABEL') {
  187. return array(0, $stack, $shallow, $deep);
  188. }
  189. if ($action == 'HALT') {
  190. return array(1);
  191. }
  192. if ($action == 'PUSH') {
  193. array_push($stack, $immediate);
  194. return array(0, $stack, $shallow, $deep);
  195. }
  196. if ($action == 'POP') {
  197. array_pop($stack);
  198. return array(0, $stack, $shallow, $deep);
  199. }
  200. if ($action == 'DUP') {
  201. $a = array_pop($stack);
  202. array_push($stack, $a);
  203. array_push($stack, $a);
  204. return array(0, $stack, $shallow, $deep);
  205. }
  206. if ($action == 'STORE') {
  207. $a = array_pop($stack);
  208. $b = array_pop($stack);
  209. $shallow[$a] = $b;
  210. return array(0, $stack, $shallow, $deep);
  211. }
  212. if ($action == 'LOAD') {
  213. $a = array_pop($stack);
  214. array_push($stack, isset($shallow[$a]) ? $shallow[$a] : 0);
  215. return array(0, $stack, $shallow, $deep);
  216. }
  217. if ($action == 'WRITE') {
  218. $a = array_pop($stack);
  219. $b = array_pop($stack);
  220. $deep[$a] = $b;
  221. return array(0, $stack, $shallow, $deep);
  222. }
  223. if ($action == 'READ') {
  224. $a = array_pop($stack);
  225. array_push($stack, isset($deep[$a]) ? $deep[$a] : 0);
  226. return array(0, $stack, $shallow, $deep);
  227. }
  228. if ($action == 'SWAP1') {
  229. $a = array_pop($stack);
  230. $b = array_pop($stack);
  231. array_push($stack, $a);
  232. array_push($stack, $b);
  233. return array(0, $stack, $shallow, $deep);
  234. }
  235. if ($action == 'SWAP2') {
  236. $a = array_pop($stack);
  237. $b = array_pop($stack);
  238. $c = array_pop($stack);
  239. array_push($stack, $a);
  240. array_push($stack, $b);
  241. array_push($stack, $c);
  242. return array(0, $stack, $shallow, $deep);
  243. }
  244. if ($action == 'SWAP3') {
  245. $a = array_pop($stack);
  246. $b = array_pop($stack);
  247. $c = array_pop($stack);
  248. $d = array_pop($stack);
  249. array_push($stack, $a);
  250. array_push($stack, $c);
  251. array_push($stack, $b);
  252. array_push($stack, $d);
  253. return array(0, $stack, $shallow, $deep);
  254. }
  255. }

执行结果:

  1. stack:
  2. -- PUSH 0
  3. stack: 0
  4. -- LOAD
  5. stack: 2000
  6. -- PUSH 1000
  7. stack: 2000, 1000
  8. -- GT
  9. stack: 0
  10. -- JMPZ 1000
  11. -- LABEL 1000
  12. stack:
  13. -- PUSH 1
  14. stack: 1
  15. -- LOAD
  16. stack: 7440
  17. -- PUSH 200
  18. stack: 7440, 200
  19. -- SWAP1
  20. stack: 200, 7440
  21. -- WRITE
  22. stack:
  23. array(2) {
  24. [7440]=>
  25. string(3) "200"
  26. [6508]=>
  27. int(200)
  28. }